package com.mall.common.core.utils.file;

import com.mall.common.core.asserts.ApiAssert;
import com.mall.common.core.enums.ErrorCodeEnum;
import com.mall.common.core.utils.EncryptUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * 文件上传工具类
 *
 * @author Sam
 */
public class FileUploadUtils {
    /**
     * 默认大小 50M
     */
    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;

    /**
     * 默认的文件名最大长度 100
     */
    public static final int DEFAULT_FILE_NAME_LENGTH = 100;

    /**
     * 根据文件路径上传
     *
     * @param baseDir 相对应用的基目录
     * @param prefix  资源路径前缀
     * @param file    上传的文件
     * @return 文件名称
     * @throws IOException
     */
    public static String upload(String baseDir, String prefix, MultipartFile file) throws IOException {
        return upload(baseDir, prefix, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
    }

    /**
     * 文件上传
     *
     * @param baseDir          相对应用的基目录
     * @param prefix           资源路径前缀
     * @param file             上传的文件
     * @param allowedExtension 上传文件类型
     * @return 返回上传成功的文件名
     * @throws IOException 比如读写文件出错时
     */
    public static String upload(String baseDir, String prefix, MultipartFile file, String[] allowedExtension) throws IOException {
        ApiAssert.notNull(ErrorCodeEnum.PHO_INTERNAL_SERVER_ERROR.convert("文件为空"), file);
        int fileNameLength = file.getOriginalFilename().length();
        ApiAssert.isFalse(ErrorCodeEnum.PHO_INTERNAL_SERVER_ERROR.convert("文件名过长 最长：" + FileUploadUtils.DEFAULT_FILE_NAME_LENGTH + "，当前：" + fileNameLength),
                fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        assertAllowed(file, allowedExtension);
        String fileName = extractFilename(file);
        File desc = getAbsoluteFile(baseDir, fileName);
        file.transferTo(desc);
        //设置权限
        Set<PosixFilePermission> perms = new HashSet<>();
        perms.add(PosixFilePermission.OWNER_READ);
        perms.add(PosixFilePermission.OWNER_WRITE);
        perms.add(PosixFilePermission.GROUP_READ);
        perms.add(PosixFilePermission.OTHERS_READ);
        Files.setPosixFilePermissions(Paths.get(desc.getAbsolutePath()), perms);
        return getPathFileName(prefix, fileName);
    }

    /**
     * 编码文件名
     */
    public static String extractFilename(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
//        fileName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")) + "/" + encodingFilename(fileName) + "." + extension;
        fileName = encodingFilename(fileName) + "." + extension;
        return fileName;
    }

    private static File getAbsoluteFile(String uploadDir, String fileName) throws IOException {
        File desc = new File(uploadDir + File.separator + fileName);
        if (!desc.getParentFile().exists()) {
            desc.getParentFile().mkdirs();
        }
        if (!desc.exists()) {
            desc.createNewFile();
        }
        return desc;
    }

    private static String getPathFileName(String prefix, String fileName) {
        return prefix + "/" + fileName;
    }

    /**
     * 编码文件名
     */
    private static String encodingFilename(String fileName) {
        fileName = fileName.replace("_", " ");
        //System.nanoTime() 纳秒 1纳秒=0.000001 毫秒
        fileName = EncryptUtils.toMD5(fileName + System.nanoTime());
        return fileName;
    }

    /**
     * 文件大小校验
     *
     * @param file             上传的文件
     * @param allowedExtension 上传文件类型
     * @return
     */
    public static void assertAllowed(MultipartFile file, String[] allowedExtension) {
        long size = file.getSize();
        ApiAssert.isFalse(ErrorCodeEnum.PHO_INTERNAL_SERVER_ERROR.convert("超出最大上传大小" + DEFAULT_MAX_SIZE / 1024 / 1024), DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE);
        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
        //文件校验异常
        String msg = "filename : [" + fileName + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]";
        ApiAssert.isFalse(ErrorCodeEnum.PHO_INTERNAL_SERVER_ERROR.convert(msg), allowedExtension != null && !isAllowedExtension(extension, allowedExtension));
    }

    /**
     * 判断MIME类型是否是允许的MIME类型
     *
     * @param extension        文件后缀
     * @param allowedExtension 上传文件类型
     * @return
     */
    public static boolean isAllowedExtension(String extension, String[] allowedExtension) {
        return StringUtils.equalsAnyIgnoreCase(extension, allowedExtension);
    }

    /**
     * 获取文件名的后缀
     *
     * @param file 表单文件
     * @return 后缀名
     */
    public static String getExtension(MultipartFile file) {
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        if (StringUtils.isEmpty(extension)) {
            extension = MimeTypeUtils.getExtension(file.getContentType());
        }
        return extension;
    }
}
